
package jard.webshop.management;

import jard.webshop.nbp.Category;
import jard.webshop.nbp.Category_;
import jard.webshop.nbp.Product;
import jard.webshop.util.Constants;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.NoResultException;
import javax.persistence.Persistence;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.Root;

/**
 *
 * @author CJP
 */
public class CategoryManagement {
    
    private static EntityManagerFactory emf = null;//Persistence.createEntityManagerFactory("jard_webshop_PU");

    public static void setEntityManagerFactory(EntityManagerFactory givenEmf) {
        emf = givenEmf;
    }
    private static CategoryManagement cm = null;

    public static CategoryManagement getInstance() {
        if (cm == null) {
            cm = new CategoryManagement();
        }
        if(emf == null) {
            emf = Persistence.createEntityManagerFactory("jard_webshop_PU");
        }
        
        return cm;
    }
    
    private CategoryManagement() {
    }
    
    public Boolean isPersisted(Category cat) {
        EntityManager em = emf.createEntityManager();


        Category fetchedCat = null;
        try {
            fetchedCat = em.find(Category.class, cat.getId());
        } catch (NoResultException e) {
            return false;
        }

        return fetchedCat != null;
    }
    
    public List<Category> getCategoriesByName(String name) {
        EntityManager em = emf.createEntityManager();
        CriteriaBuilder crit = em.getCriteriaBuilder();
        CriteriaQuery<Category> query = crit.createQuery(Category.class);
        Root<Category> c = query.from(Category.class);
        ParameterExpression<String> param = crit.parameter(String.class);

        Expression<String> lowerCaseProductName = crit.lower(c.get(Category_.name));
        Expression<String> lowerCaseParam = crit.lower(param);
        Expression<Boolean> nameRequirement = crit.equal(lowerCaseProductName, lowerCaseParam);
        query.select(c).where(nameRequirement);

        TypedQuery<Category> finalQuery = em.createQuery(query);
        finalQuery.setParameter(param, name);
        List<Category> products = finalQuery.getResultList();

        return products;
    }
    
    public void addCategory(Category category) {
        EntityManager em = emf.createEntityManager();

        if (category.getId() != null && isPersisted(category)) {
            return;
        } else {
            EntityTransaction tx = em.getTransaction();
            tx.begin();
            //System.out.println("em.contains(product) => " + em.contains(product));
            em.persist(category);
            tx.commit();
        }
    }

    public Boolean removeIfOrphan(Category category) {
        if(category.getSubcategories().isEmpty() == false) {
            return Boolean.FALSE;
        }
        EntityManager em = emf.createEntityManager();

        TypedQuery<Product> query = em.createQuery("SELECT p FROM Product P WHERE p.category.id = " + category.getId(), Product.class);
        List<Product> results = null;
        try {
            results = query.getResultList();
        } catch (NoResultException e) {
            results = new ArrayList<Product>();
        }
        if (results.isEmpty()) {
            EntityTransaction tx = em.getTransaction();
            tx.begin();
            Category parent = category.getParent();
            if(parent != null) {
                parent = em.merge(parent);
                parent.removeSubcategory(category);
            }
            em.remove(em.merge(category));
            tx.commit();
            //System.out.println("cm.isPersisted(category) => " + cm.isPersisted(category));
            return Boolean.TRUE;
        } else {
            return Boolean.FALSE;
        }

    }
    
    public List<Category> getRootcategories() {
        EntityManager em = emf.createEntityManager();
        TypedQuery<Category> query = em.createNamedQuery(Constants.GET_ROOT_CATS, Category.class);
        try {
            List<Category> retVal = query.getResultList();
//            System.out.println("getRootcategories() debug");
//            for(Category c : retVal)
//                System.out.println("Returning category " + c);
            return retVal;
        } catch(NoResultException e) {
            return new ArrayList<Category>();
        }
    }

    public void saveCategory(Category cat) {
        EntityManager em = emf.createEntityManager();

        EntityTransaction tx = em.getTransaction();
        tx.begin();
        em.merge(cat);
        tx.commit();
    }

    public List<Category> getAllCategories() {
        System.out.println("getAllCategories");
        EntityManager em = emf.createEntityManager();
        
        TypedQuery<Category> query = em.createNamedQuery(Constants.GET_ALL_CATS, Category.class);
        query.getResultList();
        try {
            List<Category> retval = query.getResultList();
            System.out.println("getAllCategories() debug");
            for(Category c : retval)
                System.out.println("Returning category " + c);
            return retval;
        } catch(NoResultException e) {
            System.out.println("Found no categories.");
            return new ArrayList<Category>();
        }
    }
}
